using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
using Krile.Kernel.Control;
using Krile.Kernel.WindowsEx;
using Krile.Kernel.Plugin.Operations;
using Krile.Kernel.Plugin;

namespace Krile.Forms.ConfigForm
{

    public partial class Config : Form
    {
        private class CfgTreeNode : TreeNode
        {
            private ConfigPage hasCp;
            public ConfigPage ConfigPage
            {
                get { return hasCp; }
                set { hasCp = value; }
            }

            public CfgTreeNode(string text)
                : base(text)
            {
                hasCp = null;
            }
            public CfgTreeNode(string text, ConfigPage cp)
                : base(text)
            {
                hasCp = cp;
            }
        }

        public Config()
        {
            InitializeComponent();
            this.UseAdvancedSetting.Checked = Core.Config.State.UseAdvancedConfig;
            ConfigPageList.Nodes.Clear();
            if (Core.Config.State.UseAdvancedConfig)
                BuildTreeAdvanced();
            else
                BuildTree();
            BuildPluginTree();
        }

        public void BuildTree()
        {
            //Node Construction
            var Appearance = new CfgTreeNode(Lang.Config.Node_Appearance, new Children.Appearance());
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Renderer, new Children.Rendering()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Color, new Children.Colors()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Tab, new Children.TabAppearance()));
            ConfigPageList.Nodes.Add(Appearance);

            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Network, new Children.Network()));

            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Timeline, new Children.Timeline()));

            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Behavior, new Children.Simplized.SimpleBehavior()));
            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_B_KeyAssign, new Children.KeyAssignment()));
        }

        public void BuildTreeAdvanced()
        {
            //Node Construction
            var Appearance = new CfgTreeNode(Lang.Config.Node_Appearance, new Children.Appearance());
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Renderer, new Children.Rendering()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_RenderArea, new Children.RenderArea()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Color, new Children.Colors()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Tab, new Children.TabAppearance()));
            Appearance.Nodes.Add(new CfgTreeNode(Lang.Config.Node_A_Detail, new Children.AppearanceDetail()));
            ConfigPageList.Nodes.Add(Appearance);

            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Network, new Children.Network()));
            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Timeline, new Children.Timeline()));
            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_Security, new Children.Security()));

            var Behavior = new CfgTreeNode(Lang.Config.Node_Behavior, new Children.Behavior());
            Behavior.Nodes.Add(new CfgTreeNode(Lang.Config.Node_B_System, new Children.SystemBehavior()));
            Behavior.Nodes.Add(new CfgTreeNode(Lang.Config.Node_B_Notification, new Children.Notification()));
            ConfigPageList.Nodes.Add(Behavior);
            ConfigPageList.Nodes.Add(new CfgTreeNode(Lang.Config.Node_B_KeyAssign, new Children.KeyAssignment()));
        }

        public void BuildPluginTree()
        {
            Dictionary<string, Dictionary<string, ConfigPage>> cfgdicts = Core.PluginManager.GetConfigPages();
            foreach (string dictkey in cfgdicts.Keys)
            {
                CfgTreeNode cpNode = null;
                var targetPlugin = Core.PluginManager.Lookup(dictkey);
                var agent = targetPlugin.Operation as IAgent;
                if (targetPlugin.Operation.OperationType == Operation.OperationTypes.Agent && agent != null)
                {
                    cpNode = new CfgTreeNode(Core.PluginManager.Lookup(dictkey).Name,
                        new Children.PluginColorOverride(agent.HostingService.Id));
                }
                else
                {
                    cpNode = new CfgTreeNode(Core.PluginManager.Lookup(dictkey).Name);
                }
                if (cfgdicts[dictkey] != null && cfgdicts[dictkey].Count > 0)
                {
                    foreach (string cpkey in cfgdicts[dictkey].Keys)
                    {
                        cpNode.Nodes.Add(new CfgTreeNode(cpkey, cfgdicts[dictkey][cpkey]));
                    }
                }
                ConfigPageList.Nodes.Add(cpNode);
            }
            try
            {
                ConfigPageList.SelectedNode = ConfigPageList.Nodes[0];
            }
            catch (ArgumentOutOfRangeException)
            {
                MessageBoxEx.Show(
                    "Configuration dialog initialization failed.",
                    @"You must restart Krile.
                    If this phenomenon raise up again and again, you should re-install Krile.", "Init error",
                    MessageBoxEx.MessageBoxExButtons.Close, MessageBoxEx.MessageBoxExIcon.Error);
            }
        }

        string ConfigTitle = "Config";
        private void TitlePictureBox_Paint(object sender, PaintEventArgs e)
        {
            using (Brush b = new LinearGradientBrush(TitlePictureBox.ClientRectangle, Color.RoyalBlue, SystemColors.Control, LinearGradientMode.Horizontal))
            {
                e.Graphics.FillRectangle(b, TitlePictureBox.ClientRectangle);
            }
            using (Font f = new Font(this.Font.FontFamily, 12F, FontStyle.Bold))
            {
                TextRenderer.DrawText(
                    e.Graphics,
                    ConfigTitle,
                    f,
                    TitlePictureBox.ClientRectangle,
                    Color.White,
                    TextFormatFlags.EndEllipsis | TextFormatFlags.Left | TextFormatFlags.NoPrefix | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
            }
        }

        CfgTreeNode prevNode = null;
        ConfigPage prevPage = null;
        private void ConfigPageList_AfterSelect(object sender, TreeViewEventArgs e)
        {
            //change selected page

            if (prevPage != null)
                prevPage.Visible = false;

            //If prev selected node isn't current item's parent,
            //collapse prev selected node 
            if (prevNode != null && e.Node.Parent != prevNode)
                    prevNode.Collapse();

                if (e.Node.Parent == null)
                    ConfigTitle = ConfigPageList.SelectedNode.Text;
                else
                    ConfigTitle = ConfigPageList.SelectedNode.Parent.Text + " - " + ConfigPageList.SelectedNode.Text;
            TitlePictureBox.Refresh();
            if (((CfgTreeNode)ConfigPageList.SelectedNode).ConfigPage != null)
            {
                ((CfgTreeNode)ConfigPageList.SelectedNode).ConfigPage.Visible = true;
                ((CfgTreeNode)ConfigPageList.SelectedNode).ConfigPage.Parent = PropertyPanel;
            }

            //set prevNode
            TreeNode node = e.Node;
            if (e.Node.Parent != null)
                node = e.Node.Parent;
            prevNode = (CfgTreeNode)node;

            //set prevPage
            if (((CfgTreeNode)e.Node).ConfigPage != null)
                prevPage = ((CfgTreeNode)e.Node).ConfigPage;
            else
                prevPage = null;

            //Expand child node
            e.Node.Expand();
        }

        private void ButtonOK_Click(object sender, EventArgs e)
        {
            foreach (CfgTreeNode node in ConfigPageList.Nodes)
                ApplyNode(node);
            this.DialogResult = DialogResult.OK;
            Core.SaveConfig(true);
            Core.FormManager.MainForm.ApplyConfig();
            this.Close();
        }

        private void ApplyNode(CfgTreeNode node)
        {
            if (node.ConfigPage != null && node.ConfigPage.IsLoaded)
                node.ConfigPage.Apply();
            foreach (CfgTreeNode cnode in node.Nodes)
                ApplyNode(cnode);
        }

        private void UseAdvancedSetting_CheckedChanged(object sender, EventArgs e)
        {
            Core.Config.State.UseAdvancedConfig = UseAdvancedSetting.Checked;
            ConfigPageList.Nodes.Clear();
            if (Core.Config.State.UseAdvancedConfig)
                BuildTreeAdvanced();
            else
                BuildTree();
            BuildPluginTree();
        }
    }
}